#pragma once
#include<iostream>
#include<pthread.h>
#include<queue>
#include"log.hpp"
#include"task.hpp"
#define NUM 6

using namespace std;

class ThreadPool{
    private:
        queue<Task> task_queue;
        pthread_mutex_t lock;
        pthread_cond_t cond;
        static ThreadPool* ptr;
        static pthread_mutex_t _lock;
    private:
        ThreadPool(){
            InltThread();
        }
        ThreadPool(const ThreadPool&)=delete;
        ThreadPool& operator=(const ThreadPool&)=delete;
    public:

        static ThreadPool* getthreadpool(){
            if(ptr==nullptr){
                pthread_mutex_lock(&_lock);
                if(ptr==nullptr){
                    ptr=new ThreadPool();
                    return ptr;
                }
                pthread_mutex_unlock(&_lock);
            }
            return ptr;
        }

        ~ThreadPool(){}

        void Lock(){
            pthread_mutex_lock(&lock);
        }
        void unLock(){
            pthread_mutex_unlock(&lock);
        }
        void threadwait(){
            pthread_cond_wait(&cond,&lock);
        }
        void threadroude(){
            pthread_cond_signal(&cond);
        }
        void Push(Task& t){
            Lock();
            task_queue.push(t);
            unLock();
            threadroude();
        }
        void Pop(Task& out){
            out=task_queue.front();
            task_queue.pop();
        }
        bool empty(){
            return task_queue.size()==0? true : false;
        }
        void InltThread(){
            pthread_mutex_init(&lock,nullptr);
            pthread_cond_init(&cond,nullptr);
            for(int i=0;i<NUM;i++){
                pthread_t pid;
                if(pthread_create(&pid,nullptr,Hander,this)!=0){
                    LOG(ERROR,"pthread_create error");
                    break;
                }
                pthread_detach(pid);
            }
        }
        static void* Hander(void* agr){
            ThreadPool* tp=(ThreadPool*)agr;

            while(true){
                Task t;
                tp->Lock();
                if(tp->empty()){
                    tp->threadwait();
                }
                tp->Pop(t);
                tp->unLock();
                t.Hander();
            }
        }
};
ThreadPool* ThreadPool::ptr=nullptr;
pthread_mutex_t  ThreadPool::_lock=PTHREAD_MUTEX_INITIALIZER;

